Welcome to the beta version of RPNCalc, yet-another-calculator-program for the NeXT Computer. Its language RPN Forth is by no means a full Forth implementation. In some ways it resemble Forth, hence the name, but in fact it is something slightly different. Used to my HP48SX I needed a RPN Calculator (Ever tried to use a 'normal' calculator when used to RPN? Like programming in Cobol, gahh...) and all these calculators out there does not have the features I want from my calculator or will cost a fortune. Mathematica
\f0 or Maple V
\f0 looks like too oversized ,the word for this seems to be kind of "Numeric Overkill", and so I went out to make my own.\
I wrote this program to suit my own needs. It was originally never meant to be released to public and some quirks in the user interface and Forth-RPN language still remain. \
However I think this hack works 99% of the time and it works well too. So I release this program free for personal use, in the hope it will serve a purpose and at least one user will find it useful. Please read the licence agreement before use.\
This version is not fully tested, some functions are implemented in a brain-dead way and must be completely rewritten soon. Use this calculator only for evaluation purpose. If you find an error, please mail a short description to me. I want to improve RPNCalc in many ways, if you find something is missing just mail. If you have a piece of code of your own and you wish me to implement it in RPNCalc just mail. If you want to say how good and amazing this program is just mail. Regardless of the remaining problems I hope you will like RPNCalc.\
Frank Siegert, 29. Oct 1992\
When reading this text, please keep in mind that english is not my native language.\
\b Hint Hint:\
\b0 \
Top-of-Stack type can be one of:
\b Int
\b0 (Integer signed 32 bit),
\b Dbl
\b0 (Double float),
\b Str
\b0 (String),
\b Obj
\b0 (Object, that is a separate stack for matrix operations),
\b Cx
\b0 (Complex value) or
\b Em
\b0 (Empty Stack)
\b0 To define a funtion key, press the Define key and then the F key you want to define. Defines are local for every user of RPNCalc. \
To give RPNCalc a fixed set of functions at startup, you can specify a startup file in the Preferences. This is local for every user of RPNCalc too.\
\b0 Control-click-drag in the data stack overview can be used to shuffle the stack.\
Double-click in the data stack overview reinputs the element.
\b0 You can always break out of a running function by pressing ESC.
\f3\b Work only if autovar is enabled and "test" is no valid function\
name. This is a shortcut to get\
variables quickly in the calculator display. See autovar.\
\f2\b0 \
Note: Whenever floats or intergers are used as a variable name, the "real" name is constructed by converting the number to a string and adding this string to the string value contents of variable "defvar". "defvar" is set to "var" as default, but this may be changed. The variable "defvar" cannot be destroyed.\
\f3\b "Hubba" get variables must exist before use\
\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 the function test take the first stack element and loop until it reach1000.\
since go or return just do nothing if the address stack is empty. Warning: If the address stack contains a return address this is used for the return.... Sometimes not what you want... a
\f3\b areset
\f2\b0 command can help in this case.\
Someday you will get tried from typing all this getadr t call stuff, why not defining it as a exec function:\
The callback function: Unlike call returns callback to itself, takes the first data stack element and jumps if true to the address on the top of the address stack, if any. Actually this function was a mistake (just forgot to calculate the return address correct), but I left this function in the language anyway.\
This way the subroutine or caller can leave a function-to-be-called-next on the address stack and return with t on the data stack, a single callback will do the rest.\
\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f2\b0\fc0\cf0 to set Edit.app the target application. To open a new window in Edit and send the whole stack we can use this code fragment:\
\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f2\b0\fc0\cf0 Well, now we reached a point where we may want to call a external program, maybe to flood the stack with the contents of your directory, well just type:\
\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\f2\b0\fc0\cf0 Now telnet is started and kept open, in contrast sysexec just execute and return. You can send data to the opened process by\
\f2\b0 This function was originally implemented to run gnuplot from RPNCalc. If you do not like the returning data to be pushed to the data stack set autopush to false. \
\f3\b f autopush
\f2\b0 \
Now, all return from the subprocess will be pushed to hyperspace.
- Floats values are doubles, described in the man page for 'math', man 3 math\
- Complex values consist of two double values\
- Strings can have arbitary length and are zero limited.*
\f2\fs20 \
\f0\fs24 - Variables and functions are defined global.
\f2\fs20 \
* functions can only handle 1024 byte strings at the moment.\
\f0\b\fs24 F = double float, I = Integer, C = Complex, S = String element\
Operators On data stack Comments\
Before After\
COMMENTS\
\b0 /*/ This is a comment /*/ Comments start and end with "/*/"\
PUSH VALUES TO DATA STACK:\
\b0 double number - -> 1F push the number as double value on the data stack, separator is , or . depending on your keyboard settings.
\b0 0xnumber - -> 1I push the hexadecimal number as\
integer on the data stack.\
0onumber - -> 1I push the octal number as\
integer on the data stack.\
0bnumber - -> 1I push the binary number as\
integer on the data stack.\
number - -> 1I same for decimal\
double,double - -> 1C push the number as\
two double values,\
a complex number,\
on the data stack\
"a String" - -> 1S push the string on\
the data stack\
systime - -> 1I push the current time\
in seconds from 1970\
(see man 3 time)\
time - -> 1S push the current time\
in ASCII format as string\
(see man 3 time)\
ddepth - -> 1I push curent depth of\
data stack to data stack\
adepth - -> 1I push curent depth of\
address stack to data stack\
t - -> 1I same as 0x1\
f - -> 1I same as 0x0\
\b CONVERTING DATA STACK ELEMENTS\
\b0 \
float 1I -> 1F convert top of stack integer element to double float\
hex 1I -> 1S convert top of stack integer element to\
hexadecimal string\
oct 1I -> 1S convert top of stack integer element to\
octal string\
bin 1I -> 1S convert top of stack integer element to\
binary string, only the 16 lowest bits\
bin32 1I -> 1S convert top of stack integer element to\
binary string, all 32 bits\
For conversion of floats or complex values read the next paragraph.\
\b ARITHMETIC AND LOGIC OPERATIONS:\
\b0 \
+ 2 -> 1 IFSC addition, strings work\
- / * 2 -> 1 IFC arithmetic operators,\
& | ^ 2 -> 1 I logical operators\
! 1 -> 1 I not operator\
== 2 -> 1I IFSC compare operators\
< > >= <= 2 -> 1I IFS compare operators\
\b0 shr, shl 2 -> 1 I shift right, shift left\
rad2grad 1F -> 1F rad to grad conversion\
grad2rad 1F -> 1F grad to rad conversion\
rint 1F -> 1I see man 3 math\
floor 1F -> 1I \
ceil 1F -> 1I \
fabs 1F -> 1F \
sqrt 1FC -> 1FC \
cbrt 1F -> 1F \
sin, cos, tan 1F -> 1F\
asin, acos, atan 1F -> 1F \
sinh,cosh,tanh 1F -> 1F \
asinh,acosh,atanh 1F -> 1F \
erf 1F -> 1F\
exp 1F -> 1F \
log 1F -> 1F\
log10 1F -> 1F\
logb 1F -> 1F \
copysign 2F -> 1F\
lgamma 1F -> 1F\
hypot 2F -> 1F\
bessely 1I 1F -> 1F\
besselj 1I 1F -> 1F\
power 2F -> 1F\
drem 2F -> 1F \
finite 1F -> 1I\
re 1C -> 1F real part of complex\
im 1C -> 1F im part of complex\
Cconjugate 1C -> 1C conjugate complex\
Cconstruct 2F -> 1C build complex from floats coordinates\
Cpconstruct 2F -> 1C build complex from amplitude and phase\
Cphase 1C -> 1F phase of complex\
Cscale 1C 1F -> 1C multiply scalar with complex\
randomfloat - -> 1F random number\
randomint - -> 1I random number\
randomcomplex - -> 1C random number\
randomseed 1I -> - seed random generator\
\b BASIC FORTH COMMANDS\
\b0 \
drop 1 -> - IFSC drop data
\b0 dup 1 -> 2 IFSC duplicate \
swap 2 -> 2 IFSC swap\
rot 3 -> 3 IFSC rotate top 3 elements\
copy 1I -> 1 IFSC get Nth element from the data stack\
turn - -> - turn data stack\
if 1I -> - conditional clause start\
else - begin of else part of conditional \
endif - end of conditional\
If clauses can be nested as deep as you like. \
\b CALLING OF FUNCTIONS
\b0 \
getadr 1S -> [adr] Push address of dictentry to\
address stack\
pusha
\fs20 or
\fs24 do - -> [adr] pushes current pc to\
address stack\
dropa [adr] -> - drops the entry on the top of the address stack\
popa2d [adr] -> 1S pop address stack entry into \
a special string value and push it\
on the data stack\
pushd2a 1S -> [adr] pop a special string value from\
the data stack and push it as address\
on the address stack
\b0 go
\fs20 or
\fs24 while 1I -> - if poped Integer true goto the position pointed by top of adress stack \
and pops position from address stack\
return - -> - goto the position pointed by top of \
adress stack and pops position from address stack, same as "t go"\
call 1I -> - if true goto to position pointed by top of the address stack, pop this from the address stack and push the address of the next command to it \
callback 1I -> - same as call but push the address of the callback to the address stack\
aremember remember the depth of the address stack.\
arecall recall the depth of the address stack, work only if current stack is deeper \
than remembered stack. This does not \
change the stack but the stackpointer.\
\b CLEARING THE STACKS
\b0 \
dreset - clear the data stack\
areset - clear the address stack\
ireset - clear the if-else-endif stack, close every if case\
restoredstack - restore the data stack to the state at the moment the FORTH engine was called, very useless when executed in\
Interactive mode since the stack will \
be restored to the same state.\
\b IDENTIFICATION OF ELEMENTS\
\b0 elemtype - -> 1I IFCS push an integer value to the data \
stack:\
0 if Top-Of-Stack element is an integer\
1 if Top-Of-Stack element is a float
\b0 2 if Top-Of-Stack element is complex\
3 if Top-Of-Stack element is a string\
4 if Top-Of-Stack element is an object\
and -1 if stack is empty\
\b PRINTING RESULTS\
\b0 print 1IFSC -> - pops and display value from top of\
data stack\
. or , 1IFCS -> - shortcut for print, character depends \
on the Keyboard settings in the \
preferences\
printf 1S, 1IFSC -> - pops and display value from top of\
data stack using a format string.\
The format string must be printf alike and only one value (top-of-stack) is \
printed.\
sprint
\fs20 or
\fs24 sprintf same as the print/printf counterpart except that a string element is created\
\b DEALING WITH VARIABLES\
\b0 \
set 1IFSC,1IFSC -> - pop value from stack and put it into \
variable defined by 2th arg\
get 1IFSC -> 1 push variable to stack\
forget 1IFS C -> - remove variable from memory\
listvars list all defined variables\
autovar 1I -> - switch the use name-as-var-if-not-in- dict feature on or off, default is on.\
\b DEFINITION AND EXECUTION OF FUNCTIONS\
\b0 \
:<name> start definition of a FORTH function\
; end definition of a FORTH function\
<name> execute the defined FORTH function\
forgetdict 1S -> - delete FORTH definition from dict\
cleardict erease all defined FORTH functions\
listdict list all defined FORTH functions\
?:<name> print this FORTH function.\
There is a difference in executing to calling: A call push a return address to the address stack, an exec simply change the context to the given function and return automagically to the caller context at the end.\
\b STRING HANDLING (limited to 1024 byte length of string at the moment)\
\b0 \
== 1S 1S -> 1I string compare\
+ 1S 1S -> 1S add two strings\
strlen 1S -> 1I take string and push its length in bytes\
getsubstr 1S (1I) 1I -> 1S get substring starting at a position (1st arg) and for a length (2nd arg), if no second argument is given a length of 1 is assumed.\
setsubstr 1S 1S 1I -> 1S set substring at position (1st arg), resize the string if needed\
breakup 1S 1S -> .... use argument one as delimiter and break the string up \
eval 1S -> .... treats the string as input for the FORTH engine\
frame 1S -> 1S put the string in "" pairs for eval and \
change \\n and \\t to literals\
instr 1S 1S -> 1I push the count of substrings (1st arg)\
found in the string (2nd arg)\
str2int 1S -> nI convert a string to integers (chars),\
null at string end is converted too!\
int2str nI 1I -> 1S build a string from integers, 1st arg is length. Null is not needed at end.\
\b EXTERNAL COMMUNICATION\
\b0 \
sysexec 1S -> ... calls UNIX command defined in string and push the return arguments as string to the stack.\
settarget 1S -> - set target application for emit command\
emit 1S -> - send string to remote application by faking key down events, not very nice but it works, anyone knows how to make it better? If yes, please send me a mail. This was borrowed from a little program I found in the newsgroup next.programmers from Dave Griffiths [dave%prim@ germany.eu.net].\
Use "!C" to send CMD-keys, like\
"!Cn" for faking CMD-n, etc...\
Of course "!!" send a '!' char.\
sysproc 1S -> ... Ah! Features! Open a subprocess\
shell (/bin/sh) and give the arg to it. All output from the shell process is directed to the data stack. \
pemit 1S -> - send the string to the subprocess shell\
autopush 1I -> - if true send output from subprocess to\
data stack, default is false\
\b OTHER COMMANDS\
\b0 \
dictinfo show system statistics \
trace toggle trace on/off\
loadimage - -> - load dumped functions from file\
dumpimage - -> - dump all defined functions to file\
Ask for file name by using a open\
or save panel\
copyright - -> - print my email address\
help - -> - nothing useful at the moment\
Note: You can always break out of a running FORTH function by pressing ESC.
\f2\fs20 \
\f0\b\fs24 Known bugs and problems in this version:\
\b0\fs20 \
- Well, it's beta software, you know what I mean: dirty, untested, unstable and buggy. \
---> Lots of bugs in any colour and size to be expected.\
- The different handling of integers and floats is not very nice, I am working on a better solution.\
- The string handing is not finished, strings are limited to 1024 bytes in the functions since these are \
only a quick hack for the moment.\
- The implementation of variables and dicts is very, very slow, the interpreter is even slower. \
- The shell is limited, help is not completed yet and the documentation is virtually non-existent.\
- Variables are not dumped with dumpimage, you must set vars in dumps by editing the dump file.\
- Error and exception handling is not implemented yet.\
- Address stack has a fixed depth of 1024 entries, however If & Data stack are approx. unlimited.\
- The n-dimensional matrix functions are not fully completed yet and therefor not documented here\
The optimized FORTH-RPN engine will be avaiable soon (I hope). I plan to release the source code as Copyleft. If you are interested just write me a email. At the moment I cannot give away the source due to some heavy constructs in it (Asche auf mein Haupt).\
Thanks to Andreas Haug (andreas@atlas.physchem.chemie.uni-tuebingen.de) for his suggestions and\
Joachim F. Klausch for the opportunity to port this to NS 3.0, took about 20 minutes...\
Thanks to Dave Griffiths (dave%prim@germany.eu.net) for the code fragment about posting key event to other applications. I have used some suggestions in my own code.\
\pard\tx960\tx1920\tx2880\tx3840\tx4800\tx5760\tx6720\tx7680\tx8640\tx9600\fc0\cf0 Feel free to send
\pard\tx520\tx1060\tx1600\tx2120\tx2660\tx3200\tx3720\tx4260\tx4800\tx5320\fc0\cf0 This software is provided "as is" without warranty of any kind, either expressed or implied, including but not limited to the implied warranties of merchantability and fitness for a particular purpose.\
\b No Liability for Consequential Damages:
\b0 In no event shall the author be liable for any damages, including any lost profits, lost savings, lost data, buisness interruption or other incidential or consequential damages arising out of the use or inability to use this software, even if advised of the possiblity of such damages.\
\b0 , distributed free of charge for personal, educational, and noncommercial use.
\b It may not be sold for profit, nor incorporated in products sold for profit
\b0 without the express permission of the author. However, recognized NeXT User Groups may include it on diskettes, tapes, CD-ROMs, or other media priced above time-and-materials costs for fundraising purposes. This software may be placed on Internet archive sites or other public software archives provided that no "download" or other access charges are collected.\
If you want to use RPNCalc for commercial purposes, you must contact me before. \
\b You have read and understand
\b0 the above disclaimer. You understand that
\b you are working at your own risk
\b0 . You understand that
\b this is copyrighted software
\b0 that you may use free of charge but
\b without any warranties
\b0 .\
3. Due to the extraordinary low price ($0)
\b I cannot give support
\b0 for this program. You are on your own. However I have email and you can send bug reports and/or suggestions to me. Please, please
\b send only plain-ascii mail
\b0 otherwise my mailer cannot receive it.\
4. This licence agreement
\b is only valid for the Version 0.96
\b0 of RPNCalc. Future versions may have different licence agreements.\
I think that anyone can live with this licence agreement. If you do not accept this licence agreement you may not use this program.\
If you want to use the FORTH-RPN engine in your own programs please contact me. When everything is cleaned up, maybe I give out the source code, but at the moment this is not possible. Well, if I find time I will rewrite and clean it up a bit.\
If you think something is missing in FORTH-RPN contact me too.\